import SerializeAble from "./serialize";

export type bool = 0 | 1;

export type Collection<T> = { [key: string]: T };
export type Col<T> = Collection<T>;

export abstract class CloneAble {
    abstract clone(): CloneAble;
};

export class CtrlInfo {
    btn = 0b0;
    protected _setBit(bit, bool) {
        if (bool) {
            this.btn |= bit;
        }
        else if ((this.btn | bit) == this.btn) {
            this.btn ^= bit;
        }
    }
};

export class KeyboardInfo extends CtrlInfo {
    static readonly BIT_CTRL = 0b1;
    static readonly BIT_SHIFT = 0b10;
    static readonly BIT_ALT = 0b100;

    lastDownKeyCode = 0;
    lastUpKeyCode = 0;

    get btnCTRL() {
        return (this.btn | KeyboardInfo.BIT_CTRL) == this.btn;
    }
    set btnCTRL(bool) {
        this._setBit(KeyboardInfo.BIT_CTRL, bool);
    }
    get btnALT() {
        return (this.btn | KeyboardInfo.BIT_ALT) == this.btn;
    }
    set btnALT(bool) {
        this._setBit(KeyboardInfo.BIT_ALT, bool);
    }
    get btnSHIFT() {
        return (this.btn | KeyboardInfo.BIT_SHIFT) == this.btn;
    }
    set btnSHIFT(bool) {
        this._setBit(KeyboardInfo.BIT_SHIFT, bool);
    }
};

export enum MouseMovement {
    IDLE = 0,
    LEFT_UP,
    LEFT_DOWN,
    RIGHT_UP,
    RIGHT_DOWN,
    MOVE,
};

export class MouseInfo extends CtrlInfo {
    static readonly BIT_BTN_RIGHT = 0b1;
    static readonly BIT_BTN_LEFT = 0b10;

    loc: cc.Vec2 = cc.v2();
    delta: cc.Vec2 = cc.v2();
    dragDisLeft: number = 0; //点击后拖拽长度。
    dragDisRight: number = 0; //点击后拖拽长度。
    lastMovement = MouseMovement.IDLE;
    update(evt: cc.Event.EventMouse) {
        this.loc = evt.getLocation();
        this.delta = evt.getDelta();

        let btn = evt.getButton();
        switch (evt.type) {
            case "mousemove":
                this.lastMovement = MouseMovement.MOVE;
                break;
            case "mouseup":
                if (btn === cc.Event.EventMouse.BUTTON_LEFT) {
                    this.btnLeft = false;
                    this.lastMovement = MouseMovement.LEFT_UP;
                }
                else if (btn === cc.Event.EventMouse.BUTTON_RIGHT) {
                    this.btnRight = false;
                    this.lastMovement = MouseMovement.RIGHT_UP;
                }
                break;
            case "mousedown":
                if (btn === cc.Event.EventMouse.BUTTON_LEFT) {
                    this.btnLeft = true;
                    this.dragDisLeft = 0;
                    this.lastMovement = MouseMovement.LEFT_DOWN;
                }
                else if (btn === cc.Event.EventMouse.BUTTON_RIGHT) {
                    this.btnRight = true;
                    this.dragDisRight = 0;
                    this.lastMovement = MouseMovement.RIGHT_DOWN;
                }
                break;
        }

        //计算拖拽长度。
        if (this.btnLeft) {
            this.dragDisLeft += this.delta.len();
        }
        if (this.btnRight) {
            this.dragDisRight += this.delta.len();
        }

        return this.lastMovement;
    }

    get btnLeft() {
        return (this.btn | MouseInfo.BIT_BTN_LEFT) == this.btn;
    }
    set btnLeft(bool) {
        this._setBit(MouseInfo.BIT_BTN_LEFT, bool);
    }
    set btnRight(bool) {
        this._setBit(MouseInfo.BIT_BTN_RIGHT, bool);
    }
    get btnRight() {
        return (this.btn | MouseInfo.BIT_BTN_RIGHT) == this.btn;
    }
};

export class TouchHandle {
    dis = 0;
    loc: cc.Vec2 = null;
    delta: cc.Vec2 = null;
    id: number = 0;

    constructor(id) {
        this.id = id;
    }
};

export function DeepEqual(obj1, obj2, visited = new Map()) {
    // 检查是否为同一个引用
    if (obj1 === obj2) return true;
    // 检查是否为 null 或不同类型
    if (obj1 == null || obj2 == null || typeof obj1 !== 'object' || typeof obj2 !== 'object') {
        return false;
    }
    // 检查循环引用
    if (visited.has(obj1)) return visited.get(obj1) === obj2;
    visited.set(obj1, obj2);
    // 获取对象的键
    let keys1 = Object.keys(obj1);
    let keys2 = Object.keys(obj2);
    // 比较键的数量
    if (keys1.length !== keys2.length) return false;
    // 比较每个键的值
    for (let key of keys1) {
        if (!keys2.includes(key) || !DeepEqual(obj1[key], obj2[key], visited)) {
            return false;
        }
    }
    return true;
};

/** 深拷贝 */
export function DeepClone<T>(obj: T, visited = new Map()) {
    // 如果是基本数据类型或者 null，直接返回
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    // 如果是CloneAble对象
    if (obj instanceof CloneAble || obj instanceof SerializeAble) {
        return obj.clone();
    }
    // 如果是日期对象，返回一个新的日期对象
    if (obj instanceof Date) {
        return new Date(obj);
    }

    // 如果是正则表达式对象，返回一个新的正则表达式对象
    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }

    // 如果是循环引用，返回已克隆的对象
    if (visited.has(obj)) {
        return visited.get(obj);
    }

    // 初始化返回结果，保证数组和对象的原型不丢失
    let clone = Array.isArray(obj) ? [] : <any>{};
    visited.set(obj, clone);

    // 遍历对象的键或数组的索引
    for (let key in obj) {
        // 确保key不是原型的属性
        if (obj.hasOwnProperty(key)) {
            clone[key] = this.DeepClone(obj[key], visited);
        }
    }

    return clone;
}